package com.fub.positioning;

import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import android.util.Log;
import com.fub.guidance.Point;

public class WifiRecorder {

	public static String FILE_NAME_RECORDS = "record.txt";
	public static String FILE_NAME_REFERENCE_POINTS = "reference_points.txt";
	private static String FOLDER_NAME = "Notes";
	private FingerprintService fingerprintManager;
	private MeasurementsFilewriter measurementsFilewriter;
	private ReferencePointFilewriter referencePointFilewriter;
	private List<Measurement> loadedMeasurements;
	int currentMeasuringInList;
	private boolean isPlayingSavedMeasurings;
	private static WifiRecorder instance;
	private List<Point> estimatedRouteKnn = new ArrayList<Point>();
	private List<Point> estimatedRouteKWNN = new ArrayList<Point>();
	private int sumKWNN = 0;
	private int sumKNN = 0;

	/**
	 * Returns an instance of the wifi recorder (singleton pattern).
	 * 
	 * @param context
	 *            the application context
	 * @return an instance of the wifi recorder
	 */
	public static WifiRecorder getInstance(Context context) {
		if (instance == null) {
			instance = new WifiRecorder(context);
		}
		return instance;
	}

	private WifiRecorder(Context context) {
		this.fingerprintManager = FingerprintService.getInstance(context);
		this.measurementsFilewriter = new MeasurementsFilewriter();
		this.referencePointFilewriter = new ReferencePointFilewriter();

		this.currentMeasuringInList = 0;
	}

	public void loadMeasurements() {
		this.loadedMeasurements = this.measurementsFilewriter.loadMeasurements(
				FOLDER_NAME, FILE_NAME_RECORDS);
	}

	/**
	 * Returns an recorded route that is calculated by knn.
	 * 
	 * @return an an recorded route that is calculated by knn
	 */
	public List<Point> getEstimatedRouteKnn() {
		return this.estimatedRouteKnn;
	}

	/**
	 * Returns an recorded route that is calculated by kwnn.
	 * 
	 * @return an an recorded route that is calculated by kwnn
	 */
	public List<Point> getEstimatedRouteKWNN() {
		return this.estimatedRouteKWNN;
	}

	/**
	 * Starts the recording of measurements.
	 */
	public void startRecordMeasurements() {
		this.fingerprintManager.startRecording();
	}

	/**
	 * Stops the recording of measurements and saves the measurements to file.
	 */
	public void stopAnSaveRecordMeasurements() {
		this.fingerprintManager.stopRecording();
		this.loadedMeasurements = this.fingerprintManager
				.getRecordedMeasurements();
		this.measurementsFilewriter.saveMeasurements(this.loadedMeasurements,
				FOLDER_NAME, FILE_NAME_RECORDS);
	}

	/**
	 * Plays recorded measurements.
	 */
	public void playSavedMeasurings() {
		this.fingerprintManager.startPlayback();
		this.currentMeasuringInList = 0;
		this.sumKNN = 0;
		this.sumKWNN = 0;
		this.isPlayingSavedMeasurings = true;
	}

	/**
	 * Stops the playing of recorded measurements.
	 */
	public void stopPlayingSavedMeasurings() {
		this.fingerprintManager.stopPlayback();
		this.isPlayingSavedMeasurings = false;
		this.estimatedRouteKnn.clear();
		this.estimatedRouteKWNN.clear();

		double cuts = this.loadedMeasurements.size()
				/ FingerprintService.NUMBER_MEASUREMENTS_FOR_POSITIONING;

		double sumKWNNAverage = this.sumKWNN / cuts;
		double sumKNNAverage = this.sumKNN / cuts;

		Log.d("Recorder", "Sum Distanz kwnn:" + sumKWNNAverage + " knn"
				+ sumKNNAverage);
	}

	/**
	 * Returns true, if the recorded measurements being played.
	 * 
	 * @return true, if the recorded measurements being played
	 */
	public boolean isPlayingSavedMeasurings() {
		return this.isPlayingSavedMeasurings;
	}

	/**
	 * Returns true, if another measurement is available.
	 * 
	 * @return true, if another measurement is available
	 */
	public boolean hasNextMeasurement() {
		return (this.currentMeasuringInList < this.loadedMeasurements.size() - 1);
	}

	/**
	 * Returns the next recorded measurement.
	 * 
	 * @return the next recorded measurement
	 */
	public Measurement getNextMeasuring() {
		if (this.loadedMeasurements == null) {
			loadMeasurements();
		}
		if (this.currentMeasuringInList > 20
				&& (this.currentMeasuringInList % FingerprintService.NUMBER_MEASUREMENTS_FOR_POSITIONING) == 0) {
			Log.d("Recorder", "add knn and kwnn to list"
					+ this.currentMeasuringInList);
			this.estimatedRouteKnn.add(this.fingerprintManager
					.getKNearestNeighbour());
			this.estimatedRouteKWNN.add(this.fingerprintManager
					.getKWeightedNearestNeighbour());
		}
		Measurement measurement = null;
		if (this.currentMeasuringInList < this.loadedMeasurements.size()) {
			measurement = this.loadedMeasurements
					.get(this.currentMeasuringInList);
			this.currentMeasuringInList++;
		}
		return measurement;
	}

	/**
	 * Saves the reference points to file.
	 */
	public void saveCurrentReferencePoints() {
		List<ReferencePoint> referencePoints = this.fingerprintManager
				.getReferencePoints();
		this.referencePointFilewriter.saveReferencePoints(referencePoints,
				FOLDER_NAME, FILE_NAME_REFERENCE_POINTS);
	}

	/**
	 * Loads the reference points from file.
	 */
	public void loadSavedReferencePoints() {
		List<ReferencePoint> referencePoints = this.referencePointFilewriter
				.readReferencePoints(FOLDER_NAME, FILE_NAME_REFERENCE_POINTS);
		Log.d("Recorder", "geladen:" + referencePoints.size());
		this.fingerprintManager.replaceReferencePoints(referencePoints);
	}
}
